home *** CD-ROM | disk | FTP | other *** search
/ PC-Blue - MS DOS Public Domain Library / PC-Blue MS-DOS Public Domain Library - NYACC.iso / vol104 / grabbag.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-12-15  |  10.0 KB  |  419 lines

  1. static char *sccsid = "@(#)usq.c        1.8u (UCF) 83/09/02";
  2. /*
  3.  *   ┌───────────────────────────────────────────────────────────────────┐
  4.  *   │                                     │
  5.  *   │     EDITOR'S NOTE:                                                  │
  6.  *   │                                     │
  7.  *   │     THIS GRABBAG WAS SUPPLIED BY COMPUTER INNOVATIONS, INC.     │
  8.  *   │                                     │
  9.  *   │     THIS IS THE SOURCE CODE FOR USQ.C.  THE SOURCE    CODE FOR  SQ.C     │
  10.  *   │     ON  "DISKETTE  B"  SHOULD  BE  READ  PRIOR  TO  STUDYING THIS   │
  11.  *   │     GRABBAG.                             │
  12.  *   │                                     │
  13.  *   │     THE ROUTINE  "SQ.EXE", ON "DISKETTE B", SQUEEZES A MODULE  TO   │
  14.  *   │     CONSERVE DISKETTE SPACE.                     │
  15.  *   │                                     │
  16.  *   │     THE ROUTINE USQ.EXE, ALSO ON "DISKETTE B", UNSQUEEZES MODULES   │
  17.  *   │     SQUEEZED BY SQ.EXE.                         │
  18.  *   │                                     │
  19.  *   └───────────────────────────────────────────────────────────────────┘
  20.  *
  21.  *
  22.  *    usq.c -    CP/M compatible    file unsqueezer    utility
  23.  *
  24.  *    compile    as follows:
  25.  *    cc [-DVAX] -O usq.c -o usq
  26.  *       (define VAX only if running on VAX)
  27.  */
  28.  
  29. /*    modified by J. Chappell    02-02-84 to check if ferror occurred on    write
  30.                 02-07-84 to accept wildcards in    filenames
  31. */
  32.  
  33.  
  34. #include <stdio.h>
  35. /* #include <signal.h> */
  36. /* #include <ctype.h> */
  37.  
  38. #define    TRUE 1
  39. #define    FALSE 0
  40. #define    ERROR (-1)
  41. #define    PATHLEN    312    /* Number of characters    allowed    in pathname */
  42. #define    OK 0
  43.  
  44. #define    RECOGNIZE 0xFF76    /* unlikely pattern */
  45. #define    DLE 0x90        /* repeat byte flag */
  46. #define    SPEOF 256        /* special endfile token */
  47. #define    NUMVALS    257        /* 256 data values plus    SPEOF*/
  48. #define    LARGE 30000
  49.  
  50. #ifdef VAX   /*    then we    don't want 32 bit integers */
  51.  
  52. typedef    short INT;
  53. typedef    unsigned short UNSIGNED;
  54.  
  55. #else    /*  16 bit machines  */
  56.  
  57. typedef    int INT;
  58. typedef    unsigned UNSIGNED;
  59.  
  60. #endif
  61.  
  62. struct _sqleaf {        /* Decoding tree */
  63.     INT _children[2];    /* left, right */
  64. };
  65. struct _sqleaf Dnode[NUMVALS - 1];
  66.  
  67.  
  68. INT Bpos;        /* last    bit position read */
  69. INT Curin;        /* last    byte value read    */
  70. INT Repct;        /* Number of times to return value */
  71. INT Value;        /* current byte    value or EOF */
  72.  
  73. INT MakeLCPathname=TRUE;    /* translate pathname to lc if all caps    */
  74. INT Nlmode=FALSE;        /* zap cr's if true */
  75. INT Inbackground = FALSE;
  76.  
  77. INT getcr(), getuhuff(), portgetw();
  78.  
  79. extern int fflush(),ferror(),fclose();
  80. #define    WILDCARD TRUE
  81.  
  82. main(argc, argv)
  83. unsigned char *argv[];
  84. {
  85.     register unsigned char *cp;
  86.     register INT npats=0;
  87.     unsigned char **patts;
  88.     INT n, errorstat;
  89.  
  90. /*
  91.     if (signal(SIGINT, SIG_IGN)==SIG_IGN)
  92.         Inbackground++;
  93.     else
  94.         signal(SIGINT, SIG_DFL);
  95.     signal(SIGHUP, SIG_IGN);
  96.                     */
  97.  
  98.     errorstat=0;
  99.     if(argc<2)
  100.         goto usage;
  101.     while (--argc) {
  102.         cp = *++argv;
  103.         if(*cp == '-') {
  104.             while( *++cp) {
  105.                 switch(*cp) {
  106.                 case 'n':
  107.                     Nlmode=TRUE; break;
  108.                 case 'u':
  109.                     MakeLCPathname=FALSE; break;
  110.                 default:
  111.                     goto usage;
  112.                 }
  113.             }
  114.         }
  115.         else if( !npats    && argc>0) {
  116.             if(argv[0][0]) {
  117.                 npats=argc;
  118.                 patts=argv;
  119.             }
  120.         }
  121.     }
  122.     if(npats < 1) {
  123. usage:
  124.         fprintf(stderr,"Usage: usq [-nu] file ...\n");
  125.         fprintf(stderr,"\t-n Nlmode: remove carriage returns\n");
  126.         fprintf(stderr,"\t-u preserve Uppercase pathnames\n");
  127. #ifdef WILDCARD
  128.         fprintf(stderr,"\twildcards are acceptable in filenames.\n");
  129. #endif
  130.         exit(1);
  131.     }
  132.  
  133. #ifdef WILDCARD
  134.     for(n=0; n<npats; ++n){
  135.         unsigned char *dir(), *cp, *s;
  136.         if(cp=dir(patts[n],1)){
  137.            for(s=cp;*s;s+=(strlen(s)+1)) errorstat |= squeeze(s);
  138.            free(cp);
  139.         }
  140.         else errorstat |= squeeze(patts[n]);
  141.     }
  142. #else
  143.     for(n=0; n<npats; ++n)
  144.         errorstat |= squeeze(patts[n]);
  145. #endif
  146.  
  147.     exit(errorstat != 0);
  148. }
  149.  
  150. /*
  151.     The following code is primarily    from typesq.c and utr.c.  Typesq
  152. is a modification of USQ by Dick Greenlaw.  Those modifications    (usq
  153. to typesq) were    made by    Bob Mathias, I am responsible for the butchery
  154. done to    make it    work with cat.
  155.  
  156. */
  157.  
  158. FILE *in, *out;
  159. squeeze(fname)
  160. unsigned char *fname;
  161. {
  162.     register INT i,    c;
  163.     register unsigned char *p;
  164.     register INT numnodes;            /* size    of decoding tree */
  165.     register UNSIGNED crc;
  166.     UNSIGNED filecrc;
  167.     unsigned char origname[PATHLEN];    /* Original file name without
  168.                             drive */
  169.  
  170.     init_cr(); init_huff();    crc=0;
  171.  
  172.     if((in=fopen( fname, "rb"))==NULL) {
  173.         fprintf(stderr,    "usq: can't open %s\n", fname);
  174.         return ERROR;
  175.     }
  176.     if(portgetw(in)    != (INT) RECOGNIZE) {/*    Process    header */
  177.         fprintf(stderr,    "usq: %s is not a SQueezed file\n", fname);
  178.         return(ERROR);
  179.     }
  180.     filecrc    = (UNSIGNED) portgetw(in);    /* checksum */
  181.     p = origname;                /* Get original    file name */
  182.     do {                    /* send    it to array */
  183.         *p = getc(in);
  184.     } while(*p++ !=    '\0');
  185.  
  186.     numnodes = portgetw(in);
  187.     if(numnodes < 0    || numnodes >= NUMVALS)    {
  188.         fprintf(stderr,    "usq: %s has invalid decode tree\n", fname);
  189.         fclose(in);
  190.         return(ERROR);
  191.     }
  192.     /* Initialize for possible empty tree (SPEOF only) */
  193.     Dnode[0]._children[0] =    -(SPEOF    + 1);
  194.     Dnode[0]._children[1] =    -(SPEOF    + 1);
  195.  
  196.     for(i =    0; i < numnodes; ++i) {    /* Get decoding    tree from file */
  197.         Dnode[i]._children[0] =    portgetw(in);
  198.         Dnode[i]._children[1] =    portgetw(in);
  199.     }
  200.     /* Get translated output bytes and write file */
  201.     if(MakeLCPathname && !IsAnyLower(origname))
  202.         uncaps(origname);
  203.     for(p=origname;    *p; ++p)        /* change / to _ */
  204.         if( *p == '/')
  205.             *p = '_';
  206.     if (!Inbackground)
  207.         fprintf(stderr,    "usq: %s -> %s\n",fname,origname);
  208.     if((out=fopen(origname,    "wb"))==NULL) {
  209.         fprintf(stderr,    "usq: can't create %s\n", origname);
  210.     }
  211.     while ((c = getcr()) !=    EOF) {
  212.         crc += (UNSIGNED) c;
  213.         if ( c == '\r' && Nlmode)
  214.             continue;
  215.         if(fputc(c,out)!=c){
  216.             fclose(in);
  217.             abort("usq: error in writing file: %s\n",origname);
  218.         }
  219.     }
  220.     fclose(in);
  221.  
  222.     if(fflush(out)<0 || ferror(out)<0)
  223.         abort("usq: Error writing file: %s\n",origname);
  224.     if(fclose(out)<0)
  225.         abort("usq: Error closing file: %s\n",origname);
  226.  
  227.     if( crc    != filecrc ) {
  228.         fprintf(stderr,    "usq: bad checksum in %s\n", fname);
  229.         fflush(stdout);
  230.         return(ERROR);
  231.     }
  232.     return(OK);
  233. }
  234. /*** from utr.c    - */
  235. /* initialize decoding functions */
  236.  
  237. init_cr()
  238. {
  239.     Repct =    0;
  240. }
  241.  
  242. init_huff()
  243. {
  244.     Bpos = 99;    /* force initial read */
  245. }
  246.  
  247. /* Get bytes with decoding - this decodes repetition,
  248.  * calls getuhuff to decode file stream    into byte
  249.  * level code with only    repetition encoding.
  250.  *
  251.  * The code is simple passing through of bytes except
  252.  * that    DLE is encoded as DLE-zero and other values
  253.  * repeated more than twice are    encoded    as value-DLE-count.
  254.  */
  255.  
  256. INT
  257. getcr()
  258. {
  259.     register INT c;
  260.  
  261.     if(Repct > 0) {
  262.         /* Expanding a repeated    char */
  263.         --Repct;
  264.         return(Value);
  265.     } else {
  266.         /* Nothing unusual */
  267.         if((c =    getuhuff()) != DLE) {
  268.             /* It's not the special delimiter */
  269.             Value =    c;
  270.             if(Value == EOF)
  271.                 Repct =    LARGE;
  272.             return(Value);
  273.         } else {
  274.             /* Special token */
  275.             if((Repct = getuhuff())    == 0)
  276.                 /* DLE,    zero represents    DLE */
  277.                 return(DLE);
  278.             else {
  279.                 /* Begin expanding repetition */
  280.                 Repct -= 2;    /* 2nd time */
  281.                 return(Value);
  282.             }
  283.         }
  284.     }
  285. }
  286. /* Decode file stream into a byte level    code with only
  287.  * repetition encoding remaining.
  288.  */
  289.  
  290. INT
  291. getuhuff()
  292. {
  293.     register INT i;
  294.  
  295.     /* Follow bit stream in    tree to    a leaf*/
  296.     i = 0;    /* Start at root of tree */
  297.     do {
  298.         if(++Bpos > 7) {
  299.             if((Curin = getc(in)) == ERROR)
  300.                 return(ERROR);
  301.             Bpos = 0;
  302.             /* move    a level    deeper in tree */
  303.             i = Dnode[i]._children[1 & Curin];
  304.         } else
  305.             i = Dnode[i]._children[1 & (Curin >>= 1)];
  306.     } while(i >= 0);
  307.  
  308.     /* Decode fake node index to original data value */
  309.     i = -(i    + 1);
  310.     /* Decode special endfile token    to normal EOF */
  311.     i = (i == SPEOF) ? EOF : i;
  312.     return(i);
  313. }
  314. /*
  315.  * Machine independent getw which always gets bytes in the same    order
  316.  *  as the CP/M    version    of SQ wrote them
  317.  */
  318. INT
  319. portgetw(f)
  320. FILE *f;
  321. {
  322.     register INT c;
  323.  
  324.     c = getc(f) & 0377;
  325.     return(c | (getc(f) << 8));
  326. }
  327.  
  328.  
  329. /* make    string s lower case */
  330. uncaps(s)
  331. unsigned char *s;
  332. {
  333.     for( ; *s; ++s)
  334.         if(isupper(*s))
  335.             *s = tolower(*s);
  336. }
  337.  
  338.  
  339. /*
  340.  * IsAnyLower returns TRUE if string s has lower case letters.
  341.  */
  342. IsAnyLower(s)
  343. unsigned char *s;
  344. {
  345.     for( ; *s; ++s)
  346.         if (islower(*s))
  347.             return(TRUE);
  348.     return(FALSE);
  349. }
  350.  
  351. /*    dir: for DOS ALL
  352.  
  353.     Entry:
  354.         1. Filename possibly containing    wildcards ? and    *
  355.         2. Drive specifier flag
  356.  
  357.     Returns: Pointer to data area containing NULL terminated
  358.          list of filenames, or NULL if none found.
  359.  
  360.     Notes: User must free up data allocated    by this    function
  361.         with free() if memory is to be restored    to heap
  362.         after use.
  363.  
  364.           Drive specifier: if non-zero will    drive specifiers
  365.         will be    put on file names
  366.  
  367.           Path names: not supported
  368.  
  369. */
  370.  
  371. unsigned char *dir(filespec,drflag)
  372. unsigned char *filespec;
  373. short drflag;
  374. {
  375. #define    BLOCK 100        /* room    for fcb,dta,etc.. */
  376. #define    FIRST 0x1100        /* search first    */
  377. #define    NEXT 0x1200        /* search next */
  378. #define    CURRENT    0x19        /* get current drive */
  379. #define    PARSE 0x2900        /* parse file name */
  380. #define    SETDTA 0x1a00        /* set disk transfer address */
  381.  
  382. unsigned char *fcb,*rets,*cp,*tmp,*dta,*realloc();
  383. unsigned short mode,pos,i;
  384. struct regval {    int ax,bx,cx,dx,si,di,ds,es;} r;
  385.  
  386.   tmp=realloc(0,BLOCK);    fcb=realloc(0,BLOCK);
  387.   dta=realloc(0,BLOCK);    rets=realloc(0,BLOCK);
  388.  
  389.   segread(&r.si);            /* parse file name */
  390.   r.es=r.ds; r.si=filespec; r.di=fcb; r.ax=PARSE; sysint21(&r,&r);
  391.  
  392.   segread(&r.si);            /* set dta */
  393.   r.dx=dta; r.ax=SETDTA; sysint21(&r,&r);
  394.  
  395.   for(pos=0,mode=FIRST;;mode=NEXT){
  396.     segread(&r.si);    r.ax=mode; r.dx=fcb; sysint21(&r,&r);    /* search  */
  397.     if(r.ax&0xff==0xff)break;            /* not found */
  398.     cp=tmp;
  399.     if(drflag){                /* put on drive    specifier */
  400.         if(*dta==0)*dta=(bdos(CURRENT)&0xff)+1;
  401.         *cp++=*dta+'A'-1; *cp++=':';
  402.     }
  403.     for(i=1;i<9;i++)if(*(dta+i)!=' ')*cp++=*(dta+i); *cp++='.';
  404.     for(;i<12;i++)if(*(dta+i)!=' ')*cp++=*(dta+i); *cp='\0';
  405.     rets=realloc(rets,pos+strlen(tmp)+1);    /* store file name */
  406.     strcpy(rets+pos,tmp);
  407.     pos+=(strlen(tmp)+1);
  408.   }
  409.  
  410.   if(pos)rets=realloc(rets,pos+strlen(tmp)+1);
  411.   else free(rets);
  412.   free(fcb); free(tmp);    free(dta);
  413.   return pos ? rets: 0;
  414. }
  415.  
  416.  
  417.  
  418.  
  419.